package com.ruoyi.ring.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import com.google.gson.Gson;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.PlanStatusEnums;
import com.ruoyi.common.enums.TimeUnitEnums;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.Builder;
import com.ruoyi.ora.constant.BizConstants;
import com.ruoyi.ring.domain.RingExerciseDetail;
import com.ruoyi.ring.domain.RingExerciseInfo;
import com.ruoyi.ring.domain.RingHealthPlan;
import com.ruoyi.ring.domain.RingSportDetail;
import com.ruoyi.ring.domain.dto.GeneralSecondDTO;
import com.ruoyi.ring.domain.vo.*;
import com.ruoyi.ring.factory.AiFactory;
import com.ruoyi.ring.mapper.RingExerciseDetailMapper;
import com.ruoyi.ring.mapper.RingExerciseInfoMapper;
import com.ruoyi.ring.mapper.RingHealthPlanMapper;
import com.ruoyi.ring.mapper.RingSportDetailMapper;
import com.ruoyi.ring.service.IEventInfoSecondService;
import com.ruoyi.system.mapper.SysUserMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class EventInfoSecondServiceImpl implements IEventInfoSecondService {
    @Resource
    private RingExerciseDetailMapper exerciseDetailMapper;
    @Resource
    private RingExerciseInfoMapper exerciseInfoMapper;
    @Resource
    private RingSportDetailMapper sportDetailMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Override
    public List<TargetSituationVO> queryCalendarList(GeneralSecondDTO secondDTO) {
        RingHealthPlan healthPlan = ringHealthPlanMapper.selectOneRingHealthPlan(Builder.of(RingHealthPlan::new).with(RingHealthPlan::setDeviceSn, secondDTO.getDeviceSn()).with(RingHealthPlan::setPlanStatus, PlanStatusEnums.IN_PROGRESS.getCode()).with(RingHealthPlan::setUserId, SecurityUtils.getUserId()).build());
        List<TargetSituationVO> targetSituationVOS = new ArrayList<>();
        secondDTO.setRecordDate(new Date());
        List<Date> exerciseDetailList = exerciseDetailMapper.queryDateList(secondDTO);
        List<Date> sportDetailList = sportDetailMapper.queryDateList(secondDTO);
        List<Date> dateList = new ArrayList<>();
        dateList.addAll(exerciseDetailList);
        dateList.addAll(sportDetailList);
        if(dateList.size() > 0){
            List<Date> previousSevenDays = dateList.stream()
                    .distinct()  // 去重（基于Date的equals方法）
                    .sorted(Date::compareTo)  // 按日期自然顺序（正序）排序
                    .collect(Collectors.toList());
            for (Date date : previousSevenDays){
                secondDTO.setRecordDate(date);
                TargetSituationVO targetSituationVO = new TargetSituationVO();
                List<RingExerciseDetail> exerciseDetails = exerciseDetailMapper.querySportHeartRate(secondDTO);
                List<RingSportDetail> sportDetails = sportDetailMapper.queryRingSportDetailList(secondDTO);
                int steps = Convert.toInt(exerciseDetails.stream().mapToInt(d -> Math.toIntExact(d.getSteps())).sum());
                steps += Convert.toInt(sportDetails.stream().mapToInt(d -> Math.toIntExact(d.getSteps())).sum());

                int calories = Convert.toInt(exerciseDetails.stream().mapToInt(d -> Math.toIntExact(d.getCalories())).sum());
                calories += Convert.toInt(sportDetails.stream().mapToInt(d -> Math.toIntExact(d.getCalories())).sum());
                int validTime = Convert.toInt(exerciseDetails.stream().mapToInt(d -> Math.toIntExact(d.getValidTime())).sum()) / 60;
                if(sportDetails.size() > 0){
                    RingSportDetail sportDetail = sportDetails.get(0);
                    if(!"".equals(sportDetail.getStepsList()) && sportDetail.getStepsList() != null){
                        String[] hrvInfos = sportDetail.getStepsList().replace("null", "0").split(",");//转成String数组
                        List<Integer> hrvInfoList = Arrays.stream(hrvInfos).map(Integer::parseInt).collect(Collectors.toList());
                        int timeInterval = 24*60/hrvInfoList.size();
                        int count = Convert.toInt(Convert.toLong(hrvInfoList.stream().filter(num -> num != 0 ).count()));
                        validTime = validTime + timeInterval*count;
                    }
                }

                targetSituationVO.setDailyValue(date);
                targetSituationVO.setWeek(DateUtils.queryWeekday(date));
                targetSituationVO.setSteps(steps);
                targetSituationVO.setCalorie(calories);
                targetSituationVO.setDuration(validTime);
                targetSituationVO.setStepCount(healthPlan != null ? healthPlan.getStepCount() : 0);
                targetSituationVO.setExerciseCalorie(healthPlan != null ? healthPlan.getExerciseCalorie() : 0);
                targetSituationVO.setExerciseDuration(healthPlan != null ? healthPlan.getExerciseDuration() : 0);
                targetSituationVOS.add(targetSituationVO);
            }
        }
        return targetSituationVOS;
    }
    @Override
    public EventInfoSecondVO queryEventInfoList(GeneralSecondDTO secondDTO) {
        EventInfoSecondVO eventInfoSecondVO = new EventInfoSecondVO();
        List<EventInfoSecondVO.EventInfoVO> eventInfoVOList = new ArrayList<>();
        // 步数
        int steps = 0;
        // 距离
        double distance = 0;
        // 卡路里
        int calories = 0;
        // 有效时间（分钟）
        int validTime = 0;
        //锻炼详情表
        List<RingExerciseDetail> exerciseDetails = exerciseDetailMapper.querySportHeartRate(secondDTO);
        List<RingSportDetail> sportDetails = sportDetailMapper.queryRingSportDetailList(secondDTO);

        steps = Convert.toInt(exerciseDetails.stream().filter(Objects::nonNull).filter(d -> d.getSteps() != null).mapToInt(d -> Math.toIntExact(d.getSteps())).sum());
        distance = queryBigDecimalExample(Convert.toDouble(exerciseDetails.stream().filter(Objects::nonNull).filter(d -> d.getDistance() != null).mapToInt(d -> Math.toIntExact(d.getDistance())).sum()) / 1000);
        calories = Convert.toInt(exerciseDetails.stream().filter(Objects::nonNull).filter(d -> d.getCalories() != null).mapToInt(d -> Math.toIntExact(d.getCalories())).sum());
        validTime = Convert.toInt(exerciseDetails.stream().filter(Objects::nonNull).filter(d -> d.getValidTime() != null).mapToInt(d -> Math.toIntExact(d.getValidTime())).sum()) / 60;

        steps += Convert.toInt(sportDetails.stream().filter(Objects::nonNull).filter(d -> d.getSteps() != null).mapToInt(d -> Math.toIntExact(d.getSteps())).sum());
        distance += queryBigDecimalExample(Convert.toDouble(sportDetails.stream().filter(Objects::nonNull).filter(d -> d.getDistance() != null).mapToInt(d -> Math.toIntExact(d.getDistance())).sum()) /1000);
        calories += Convert.toInt(sportDetails.stream().filter(Objects::nonNull).filter(d -> d.getCalories() != null).mapToInt(d -> Math.toIntExact(d.getCalories())).sum());

        if(TimeUnitEnums.DAY.getCode().equals(secondDTO.getType())){
            if(sportDetails.size() > 0){
                RingSportDetail sportDetail = sportDetails == null ? null : sportDetails.get(0);
                String[] stepsInfos = sportDetail.getStepsList().replace("null", "0").split(",");//转成String数组
                List<Integer> stepsInfoList = Arrays.stream(stepsInfos).map(Integer::parseInt).collect(Collectors.toList());
                int timeInterval = 24*60/stepsInfoList.size();
                int count = Convert.toInt(Convert.toLong(stepsInfoList.stream().filter(num -> num != 0).count()));
                validTime = validTime + timeInterval * count;
                // 心率数据起始时间戳
                long startMs = sportDetail.getHistoryDay().getTime();
                int intervalMs = timeInterval * 60 * 1000;
                // 计算每个数字对应的时间点
                for (int i = 0; i < stepsInfoList.size(); i++) {
                    EventInfoSecondVO.EventInfoVO info = new EventInfoSecondVO.EventInfoVO();
                    int num = stepsInfoList.get(i);
                    // 计算当前心率数据点对应的时间戳
                    long currentTimeMs = startMs + Convert.toLong(i) * Convert.toLong(intervalMs);
                    info.setTimeLabel(DateUtils.convertDateTimeToHHMM(DateUtil.date(currentTimeMs)));
                    info.setValue(num);
                    eventInfoVOList.add(info);
                }
            }
            eventInfoSecondVO.setRecordDate(DateUtils.dateTimeChinese(secondDTO.getRecordDate()));
            eventInfoSecondVO.setWeekName(DateUtils.queryWeekday(secondDTO.getRecordDate()));
        }else {
            for(RingSportDetail sportDetail : sportDetails){
                if(!"".equals(sportDetail.getStepsList()) && sportDetail.getStepsList() != null){
                    String[] hrvInfos = sportDetail.getStepsList().replace("null", "0").split(",");//转成String数组
                    List<Integer> hrvInfoList = Arrays.stream(hrvInfos).map(Integer::parseInt).collect(Collectors.toList());
                    int timeInterval = 24*60/hrvInfoList.size();
                    int count = Convert.toInt(Convert.toLong(hrvInfoList.stream().filter(num -> num != 0 ).count()));
                    validTime = validTime + timeInterval*count;
                }
            }

            if(TimeUnitEnums.WEEK.getCode().equals(secondDTO.getType())){
                steps = steps / 7;
                distance =queryBigDecimalExample(distance / 7);
                calories = calories / 7;
                validTime = validTime / 7;
                eventInfoSecondVO.setDateStart(DateUtils.dateTimeChinese(DateUtils.getSundayOfWeek(secondDTO.getRecordDate())));
                eventInfoSecondVO.setDateEnd(DateUtils.dateTimeChinese(DateUtils.getSaturdayOfWeek(secondDTO.getRecordDate())));
                List<Date> dateList = DateUtils.getWeekDatesLegacy(secondDTO.getRecordDate());
                for (Date date : dateList){
                    EventInfoSecondVO.EventInfoVO info = new EventInfoSecondVO.EventInfoVO();
                    info.setTimeLabel(DateUtils.queryWeekday(date));
                    info.setValue(Convert.toInt(exerciseDetails.stream().filter(num -> num.getRecordDate().getTime()==date.getTime()).mapToInt(d -> Math.toIntExact(d.getSteps())).sum()));
                    eventInfoVOList.add(info);
                }
            }else {
                int days = DateUtils.getDaysInMonth(secondDTO.getRecordDate());
                steps = steps / days;
                distance = queryBigDecimalExample(distance / days);
                calories = calories / days;
                validTime = validTime / days;
                eventInfoSecondVO.setDateStart(DateUtils.dateTimeChinese(DateUtils.getFirstDayOfMonth(secondDTO.getRecordDate())));
                eventInfoSecondVO.setDateEnd(DateUtils.dateTimeChinese(DateUtils.getLastDayOfMonth(secondDTO.getRecordDate())));
                List<Date> dateList = DateUtils.getMonthDatesLegacy(secondDTO.getRecordDate());
                for (Date date : dateList){
                    EventInfoSecondVO.EventInfoVO info = new EventInfoSecondVO.EventInfoVO();
                    info.setTimeLabel(DateUtils.queryMonthday(date));
                    info.setValue(Convert.toInt(exerciseDetails.stream().filter(num -> num.getRecordDate().getTime()==date.getTime()).mapToInt(d -> Math.toIntExact(d.getSteps())).sum()));
                    eventInfoVOList.add(info);
                }
            }
        }
        eventInfoSecondVO.setValidTime(validTime);
        eventInfoSecondVO.setSteps(steps);
        eventInfoSecondVO.setDistance(distance);
        eventInfoSecondVO.setCalories(calories);
        eventInfoSecondVO.setEventInfoVOList(eventInfoVOList);
        return eventInfoSecondVO;
    }

    @Override
    public EventExerciseInfoVO queryEventExerciseInfoList(GeneralSecondDTO secondDTO) {
        EventExerciseInfoVO eventExerciseInfoVO = new EventExerciseInfoVO();
        List<EventExerciseInfoJsonVO> exerciseJsonVOList = new ArrayList<>();
        List<RingExerciseDetail> list = exerciseDetailMapper.selectRingExerciseDetailList(Builder.of(RingExerciseDetail::new).with(RingExerciseDetail::setUserId, SecurityUtils.getUserId()).with(RingExerciseDetail::setRecordDate, secondDTO.getRecordDate()).build());
        int total = list.size();
        if(total > 0){
            long exerciseTime = list.stream().mapToLong(r -> r.getValidTime()).sum();// 运动时长
            long exerciseCalorie = list.stream().mapToLong(r -> r.getCalories()).sum();// 运动卡路里
            eventExerciseInfoVO.setExerciseTime(exerciseTime);
            eventExerciseInfoVO.setExerciseCalorie(exerciseCalorie);
            eventExerciseInfoVO.setTotal(total);
            for(RingExerciseDetail exerciseDetail : list){
                EventExerciseInfoJsonVO infoJsonVO;
                RingExerciseInfo exerciseInfo = exerciseInfoMapper.selectRingExerciseInfoById(exerciseDetail.getExerciseId());
                infoJsonVO = Convert.convert(EventExerciseInfoJsonVO.class,exerciseInfo);
                infoJsonVO.setDeviceSn(exerciseDetail.getDeviceSn());
                infoJsonVO.setExerciseLogo(exerciseInfo.getExerciseLogo());
                infoJsonVO.setExerciseName(exerciseInfo.getExerciseName());
                infoJsonVO.setValidTime(exerciseDetail.getValidTime());
                infoJsonVO.setCalories(exerciseDetail.getCalories());
                String[] hrvInfos = exerciseDetail.getHrList().replace("null", "0").replace("255", "0").split(",");//转成String数组
                List<Integer> hrvInfoList = Arrays.stream(hrvInfos).map(Integer::parseInt).collect(Collectors.toList());
                long average = Convert.toLong(hrvInfoList.stream().filter(num -> num != 0).mapToInt(Integer::intValue).average().orElse(0.0));
                infoJsonVO.setHrRate(average);
                infoJsonVO.setEndHi(DateUtils.calculateTimeAfterMinutes(exerciseDetail.getStartTime(),0));
                exerciseJsonVOList.add(infoJsonVO);
            }
            eventExerciseInfoVO.setExerciseJsonVOList(exerciseJsonVOList);
        }
        return eventExerciseInfoVO;
    }

    @Override
    public CompareDistanceRateVO queryCompareDistanceRate(GeneralSecondDTO secondDTO) {
        CompareDistanceRateVO compareDistanceRateVO = new CompareDistanceRateVO();
        secondDTO.setType(TimeUnitEnums.DAY.getCode());
        List<RingExerciseDetail> exerciseDetails = exerciseDetailMapper.querySportHeartRate(secondDTO);
        List<RingSportDetail> sportDetails = sportDetailMapper.queryRingSportDetailList(secondDTO);
        int steps = Convert.toInt(exerciseDetails.stream().mapToInt(d -> Math.toIntExact(d.getSteps())).sum());
        steps += Convert.toInt(sportDetails.stream().mapToInt(d -> Math.toIntExact(d.getSteps())).sum());
        SysUser sysUser = sysUserMapper.queryUserHealthQuestion(SecurityUtils.getUserId());
        String sex = "0".equals(sysUser.getSex())? "男" : "女";
        String aiContent = "通过性别："+ sex +"，走路步数："+steps+"步，一个城市预估100W人口，从以下阶段数据中获取少于"+steps+"步的人数（syrs），获取0至3000步的人数（value03），3001至6000步的人数（value36），6001至9000步的人数（value69），9001至12000步的人数（value912），12001至15000步的人数（value1215），15001至18000步的人数（value1518），>180001步的人数（value18），例如{\"syrs\":xxx,\"value03\":xxx,\"value36\":xxx,\"value69\":xxx,\"value912\":xxx,\"value1215\":xxx,\"value1518\":xxx,\"value18\":xxx}，不要其他任何内容";
        String jsonStr = AiFactory.build(BizConstants.AI_PLATFORM.getValue()).chatCompletions(aiContent);
        System.out.println(jsonStr);
        Gson gson = new Gson();
        Map<String, Object> resultMap = gson.fromJson(jsonStr, Map.class);
        int syrs = Convert.toInt(resultMap.get("syrs").toString());
        int value03 = Convert.toInt(resultMap.get("value03").toString());;
        int value36 = Convert.toInt(resultMap.get("value36").toString());;
        int value69 = Convert.toInt(resultMap.get("value69").toString());;
        int value912 = Convert.toInt(resultMap.get("value912").toString());;
        int value1215 = Convert.toInt(resultMap.get("value1215").toString());;
        int value1518 = Convert.toInt(resultMap.get("value1518").toString());;
        int value18 = Convert.toInt(resultMap.get("value18").toString());;
        int total = value03+value36+value69+value912+value1215+value1518+value18;
        int rate = Convert.toInt(total == 0 ? 0 : queryBigDecimalExample(Convert.toDouble(syrs) / Convert.toDouble(total))*100);
        compareDistanceRateVO.setSteps(steps);
        compareDistanceRateVO.setRate(rate);
        compareDistanceRateVO.setSex(sex);
        compareDistanceRateVO.setValue1(value03);
        compareDistanceRateVO.setValue2(value36);
        compareDistanceRateVO.setValue3(value69);
        compareDistanceRateVO.setValue4(value912);
        compareDistanceRateVO.setValue5(value1215);
        compareDistanceRateVO.setValue6(value1518);
        compareDistanceRateVO.setValue7(value18);

        return compareDistanceRateVO;
    }

    @Resource
    private RingHealthPlanMapper ringHealthPlanMapper;
    @Override
    public List<TargetSituationVO> queryTargetSituation(GeneralSecondDTO secondDTO) {
        RingHealthPlan healthPlan = ringHealthPlanMapper.selectOneRingHealthPlan(Builder.of(RingHealthPlan::new).
                with(RingHealthPlan::setDeviceSn, secondDTO.getDeviceSn()).
                with(RingHealthPlan::setPlanStatus, PlanStatusEnums.IN_PROGRESS.getCode()).
                with(RingHealthPlan::setUserId, SecurityUtils.getUserId()).build());
        List<TargetSituationVO> targetSituationVOS = new ArrayList<>();
        secondDTO.setType(TimeUnitEnums.DAY.getCode());
        List<Date> previousSevenDays = DateUtils.getPreviousSevenDays(secondDTO.getRecordDate());
        if(previousSevenDays.size() > 0){
            previousSevenDays = previousSevenDays.stream().sorted().collect(Collectors.toList());
            for (Date date : previousSevenDays){
                secondDTO.setRecordDate(date);
                TargetSituationVO targetSituationVO = new TargetSituationVO();
                List<RingExerciseDetail> exerciseDetails = exerciseDetailMapper.querySportHeartRate(secondDTO);
                List<RingSportDetail> sportDetails = sportDetailMapper.queryRingSportDetailList(secondDTO);
                int steps = Convert.toInt(exerciseDetails.stream().filter(Objects::nonNull).filter(d -> d.getSteps() != null).mapToInt(d -> Math.toIntExact(d.getSteps())).sum());
                steps += Convert.toInt(sportDetails.stream().filter(Objects::nonNull).filter(d -> d.getSteps() != null).mapToInt(d -> Math.toIntExact(d.getSteps())).sum());

                int calories = Convert.toInt(exerciseDetails.stream().mapToInt(d -> Math.toIntExact(d.getCalories())).sum());
                calories += Convert.toInt(sportDetails.stream().mapToInt(d -> Math.toIntExact(d.getCalories())).sum());
                int validTime = Convert.toInt(exerciseDetails.stream().mapToInt(d -> Math.toIntExact(d.getValidTime())).sum()) / 60;
                if(sportDetails.size() > 0){
                    RingSportDetail sportDetail = sportDetails.get(0);
                    if(!"".equals(sportDetail.getStepsList()) && sportDetail.getStepsList() != null){
                        String[] hrvInfos = sportDetail.getStepsList().replace("null", "0").split(",");//转成String数组
                        List<Integer> hrvInfoList = Arrays.stream(hrvInfos).map(Integer::parseInt).collect(Collectors.toList());
                        int timeInterval = 24*60/hrvInfoList.size();
                        int count = Convert.toInt(Convert.toLong(hrvInfoList.stream().filter(num -> num != 0 ).count()));
                        validTime = validTime + timeInterval*count;
                    }
                }

                targetSituationVO.setDailyValue(date);
                targetSituationVO.setWeek(DateUtils.queryWeekday(date));
                targetSituationVO.setSteps(steps);
                targetSituationVO.setCalorie(calories);
                targetSituationVO.setDuration(validTime);
                targetSituationVO.setStepCount(healthPlan != null ? healthPlan.getStepCount() : 0);
                targetSituationVO.setExerciseCalorie(healthPlan != null ? healthPlan.getExerciseCalorie() : 0);
                targetSituationVO.setExerciseDuration(healthPlan != null ? healthPlan.getExerciseDuration() : 0);
                targetSituationVOS.add(targetSituationVO);
            }
        }
        return targetSituationVOS;
    }

    @Override
    public PhysicalActivityLevelVO queryPhysicalActivityLevel(GeneralSecondDTO secondDTO) {
        return null;
    }

    public Double queryBigDecimalExample(Double num) {
        BigDecimal bd = new BigDecimal(String.valueOf(num));
        BigDecimal roundedBd = bd.setScale(2, RoundingMode.HALF_UP);
        return roundedBd.doubleValue();
    }
}
